package com.sophialex.health.record.common.bind.swt.annotations;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.UpdateValueStrategy;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;

import com.sophia.pojo.AbstractModelObject;
import com.sophialex.health.record.common.bind.swt.annotations.helper.ObjMaker;

/**
 * @author sunxq 分析注解，并通过反射完成绑定（藏污纳垢之地）
 */
public class AnnotionProcessor {
	private ViewPart view;

	private BufferedOutputStream out = null;

	private Map<String, BindingConfig> confs = new HashMap<String, BindingConfig>();

	private DataBindingContext bindingContext = new DataBindingContext();

	private Map<String, Binding> bindMap = new HashMap<String, Binding>();

	public Binding getBinding(String wegitName) {
		if(!bindMap.containsKey(wegitName))
			throw new IllegalArgumentException("并没有与" + wegitName + "对应的绑定信息，请检查拼写。");
		return bindMap.get(wegitName);
	}

	void addBinding(String wegitName, Binding bind) {

	}

	public void addConf(String uiName, BindingConfig conf) {
		Field f = null;
		List<Field> fs = getFields(view.getClass());
		for(Field f1 : fs) {
			if(f1.getName().equals(uiName)) {
				f = f1;
				break;
			}
		}

		if(f == null)
			throw new RuntimeException("类" + view.getClass().getSimpleName() + "中没有名为" + uiName + "的字段");
		// try {
		// f = view.getClass().getDeclaredField(uiName);
		// f.setAccessible(true);
		// } catch (NoSuchFieldException e) {
		// throw new RuntimeException("类" + view.getClass().getSimpleName()
		// + "中没有名为" + uiName + "的字段", e);
		// }
		// if(Control.class.isAssignableFrom(f.getType())){
		// throw new
		// RuntimeException("类"+view.getClass().getSimpleName()+"中名为"+uiName+"的字段不是控件!");
		// }
		confs.put(uiName, conf);
	}

	public AnnotionProcessor(ViewPart view) {
		super();
		this.view = view;
		out = new BufferedOutputStream(System.out);
	}

	public AnnotionProcessor(ViewPart view, OutputStream out) {
		this.view = view;
		this.out = new BufferedOutputStream(out);
	}

	void out(String s) {
		try {
			out.write(s.getBytes());
			out.flush();
		}
		catch(IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public void process() {
		out("----------------------------------------------------------------------------------------------------------------------\r\n");
		out("                                         Auto Binding of " + view.getClass().getSimpleName() + "                                 \r\n");
		out("----------------------------------------------------------------------------------------------------------------------\r\n");
		List<Field> fs = getFields(view.getClass());// view.getClass().getDeclaredFields();
		// System.out.println(fs);
		int i = 1;
		for(Field f : fs) {

			f.setAccessible(true);

			if(f.getAnnotation(BindTo.class) != null) {
				i++;
				new BindToProcesspor(view, f, this, bindingContext).process();
			}
			if(f.getAnnotation(ComboDataBindTo.class) != null) {
				i++;
				new ComboDataBindToProcessor(view, f, this).process();
			}
			if(f.getAnnotation(ListPathBindTo.class) != null) {
				i++;
				new ListPathBindToProcessor(view, f, this, bindingContext).process();
			}
			if(f.getAnnotation(ListPathComboDataBindTo.class) != null) {
				i++;
				new ListPathComboDataBindToProcessor(view, f, this).process();
			}
		}
		if(i == 1)
			out("  No fields require binding.");
		else
			this.bindingContext.updateModels();
		out("\r\n");
	}

	/**
	 * 把source的属性赋给target,并且更新ui
	 * 
	 * @param <T>
	 * @param target
	 * @param source
	 * @author Alex May 5, 2011 11:50:17 AM create
	 */
	public <T extends AbstractModelObject> void updateUI(T target, T source) {
		copyPropValue(target, source);
		bindingContext.updateTargets();
		bindingContext.updateModels();
	}
	
	public void updateModel() {
		bindingContext.updateModels();
	}

	private List<Field> getFields(Class<?> clazz) {
		List<Field> r = new ArrayList<Field>();
		Field[] fs = clazz.getDeclaredFields();
		for(Field f : fs) {
			if(clazz.equals(view.getClass())) {// 第一层
				f.setAccessible(true);
				r.add(f);
			} else {// 当前正在处理view的超类
				if(isValidFiledOfBaseClazz(f)) {
					f.setAccessible(true);
					r.add(f);
				}
			}
		}
		Class<?> sc = clazz.getSuperclass();
		if(ViewPart.class.isAssignableFrom(sc)) {
			r.addAll(getFields(sc));
		}
		return r;
	}

	private boolean isValidFiledOfBaseClazz(Field f) {
		int m = f.getModifiers();
		if(Modifier.isProtected(m) || Modifier.isPublic(m))
			return true;
		return false;
	}

	UpdateValueStrategy toTargetInstanceFor(String uiName) {
		if(confs.get(uiName) != null)
			return confs.get(uiName).updateValueStrategyOfModel();
		return null;
	}

	UpdateValueStrategy toModelInstanceFor(String uiName) {
		if(confs.get(uiName) != null)
			return confs.get(uiName).updateValueStrategyOfUi();
		return null;
	}

	public static ControlDecoration createDecorator(Text text, String message, int position) {
		ControlDecoration controlDecoration = new ControlDecoration(text, position);
		// controlDecoration.setShowHover(true);
		controlDecoration.setDescriptionText(message);
		FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_ERROR);
		controlDecoration.setImage(fieldDecoration.getImage());
		return controlDecoration;
	}

	private <T> void copyPropValue(T target, T source) {
		if(target == null)
			return;
		Object s = source;
		if(source == null) {
			try {
				Constructor<?> c = target.getClass().getConstructor();
				s = c.newInstance();
				// doCopy(target, );

			}
			catch(Exception e) {
				e.printStackTrace();
				return;
			}

		}
		if(s != null)
			doCopy(target, s);
	}

	@SuppressWarnings("unchecked")
	private void doCopy(Object target, Object source) {

		BeanInfo bi = null;
		try {
			bi = Introspector.getBeanInfo(target.getClass());
		}
		catch(IntrospectionException e2) {
			e2.printStackTrace();
			return;
		}
		PropertyDescriptor[] pds = bi.getPropertyDescriptors();
		for(int i = 0; i < pds.length; i++) {
			String propertyName = pds[i].getName();
			//System.out.println("-------------------------"+propertyName);
			if(propertyName.equals("class") || propertyName.equals("atttrMap"))
				continue;
			Method reader = pds[i].getReadMethod();
			Method setter = pds[i].getWriteMethod();
			if(!pds[i].getPropertyType().getName().startsWith("com.sophia")) {

				try {
					Object tv = reader.invoke(target);
					Object sv = reader.invoke(source);

					if(!List.class.isAssignableFrom(pds[i].getPropertyType())) {
						if(setter != null) {
							setter.invoke(target, sv);

							// 触发bean的属性监听器
							if(AbstractModelObject.class.isAssignableFrom(target.getClass())) {
								((AbstractModelObject) target).firePropertyChange(propertyName, tv, sv);
							}
						}
					} else {
						Class<?> gt = Class.forName(reader.getGenericReturnType().toString().split("<")[1].split(">")[0]);
						// Constructor sc = gt.getConstructor();
						ObjMaker maker = ObjMaker.getInstance(gt);
						if(sv == null)
							sv = new ArrayList();
						List tl = (List) tv;
						List sl = (List) sv;
						if(tl.size() >= sl.size()) {
							int jj = 0;
							for(; jj < sl.size(); jj++) {
								doCopy(tl.get(jj), sl.get(jj));
							}
							for(; jj < tl.size(); jj++) {
								doCopy(tl.get(jj), maker.newObject());
							}
						} else {
							int jj = tl.size();
							for(; jj < sl.size(); jj++) {
								tl.add(maker.newObject());
							}
							for(jj = 0; jj < tl.size(); jj++) {
								doCopy(tl.get(jj), sl.get(jj));
							}
						}
					}
				}
				catch(Exception e1) {
					e1.printStackTrace();
				}

			} else {
				Object t = null;
				Object s = null;
				try {
					t = reader.invoke(target);
					s = reader.invoke(source);
					if(t == null && s == null)
						continue;// 继续循环
					// Constructor<?> c = null;
					// c = (t == null ? s.getClass().getConstructor() : t
					// .getClass().getConstructor());
					ObjMaker maker = null;
					if(t == null) {
						maker = ObjMaker.getInstance(s.getClass());
					} else {
						maker = ObjMaker.getInstance(t.getClass());
					}
					if(s == null) {

						doCopy(t, maker.newObject());// 必须new一个当参数，否则得不到预期的行为

					} else if(t == null) {
						setter.invoke(target, maker.newObject());
						doCopy(reader.invoke(target), reader.invoke(source));
					} else {
						doCopy(reader.invoke(target), reader.invoke(source));
					}
				}
				catch(Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				// 触发bean的属性监听器
				if(AbstractModelObject.class.isAssignableFrom(target.getClass())) {
					((AbstractModelObject) target).firePropertyChange(propertyName, t, s);
				}

			}

		}
	}
}
